﻿using Red.Core.UndoRedo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Red.GameData.Actions
{
    /// <summary>
    /// Remove override from property
    /// </summary>
    public class AddArrayElement : IAction
    {
        /// <summary>
        /// Target context of objects being edited
        /// </summary>
        private Red.GameData.EditorContext _context;

        /// <summary>
        /// Id of the object to modify
        /// </summary>
        private Guid _objectID;

        /// <summary>
        /// Name of the property in the object to modify
        /// </summary>
        private string _propertyName;

        /// <summary>
        /// GUID of the array element to add
        /// </summary>
        private Guid _valueGuid;

        /// <summary>
        /// Get user name for this action
        /// </summary>
        /// <returns></returns>
        string IAction.GetDisplayName()
        {
            return "Add element to '" + _propertyName + "'"; // TODO: more descriptive please :)
        }

        /// <summary>
        /// Execute action
        /// </summary>
        bool IAction.Do(Red.Core.UndoRedo.ActionHistory history, ref string errorMessage)
        {
            // get the target object
            var obj = _context.Data.Find(_objectID);
            if (obj == null)
            {
                errorMessage = "Unable to retrieve target object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // create property holder
            var prop = obj.GetProperty(_propertyName);
            if (prop == null)
            {
                errorMessage = "Unable to retrieve property '" + _propertyName + "' for object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // add element to array
            if (null == prop.Action_AddValue("", _valueGuid))
            {
                errorMessage = "Unable to add element to array '" + _propertyName + "' for object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // action was successful
            return true;
        }

        /// <summary>
        /// Revert execution of the action
        /// </summary>
        bool IAction.Undo(Red.Core.UndoRedo.ActionHistory history, ref string errorMessage)
        {
            // get the target object
            var obj = _context.Data.Find(_objectID);
            if (obj == null)
            {
                errorMessage = "Unable to retrieve target object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // create property holder
            var prop = obj.GetProperty(_propertyName);
            if (prop == null)
            {
                errorMessage = "Unable to retrieve property '" + _propertyName + "' for object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // remove the array element, we don't care about the value (it's tracked by other undo steps)
            if (!prop.Action_RemoveValue(_valueGuid))
            {
                errorMessage = "Unable to undo adding element to array '" + _propertyName + "' for object: " + Red.GameData.Raw.Utils.FormatGuid(_objectID);
                return false;
            }

            // action was successful
            return true;
        }

        /// <summary>
        /// Construct simple action
        /// </summary>
        public static AddArrayElement Create(EditorContext context, Raw.DataObject obj, string propertyName)
        {
            var ret = new AddArrayElement();
            ret._context = context;
            ret._objectID = obj.ID;
            ret._valueGuid = Guid.NewGuid(); // this must be consistent in the whole action
            ret._propertyName = propertyName;
            return ret;
        }

    }

}
